#include <node.h>
#include <v8.h>

using namespace v8;

#define WIN32_LEAN_AND_MEAN 
#include <Windows.h>

#include <cstdlib>
#include <cstdio>
#include <cwchar>

HINSTANCE hinstance;
HWND hwnd;

int count = 0;

Persistent<Object> temp;

Handle<Value> DeleteTemp(const Arguments& args)
{
	HandleScope scope;

	temp.Dispose();

	return scope.Close(Null());
}

Handle<Value> SetTemp(const Arguments& args)
{
	HandleScope scope;

	temp = Persistent<Object>::New(args[0]->ToObject());

	return scope.Close(Null());
}

Handle<Value> GetTemp(const Arguments& args)
{
	HandleScope scope;
	
	return scope.Close(temp);
}

LRESULT WINAPI WndProc(HWND hwnd, UINT msg, WPARAM wpar, LPARAM lpar) {
	WORD x = 0x0000FFFF&lpar;
	WORD y = (0xFFFF0000&lpar)>>16;

	wchar_t buf[256];

	switch(msg)
	{
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_LBUTTONDOWN:
		count++;
		swprintf(buf,L"%d",count);
		MessageBoxW(hwnd,buf,L"",MB_OK);
		return 0;
	default:
		return DefWindowProc(hwnd, msg, wpar, lpar);
	}
}

#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480

Handle<Value> Main(const Arguments& args)
{
	HandleScope scope;

	wchar_t buf[256];
	args[0]->ToString()->Write((uint16_t*)buf);
	char title[256];
	wcstombs(title,buf,256);
	printf("program title: %s\n",title);

	//get instance
	printf("get instance...");
	hinstance = GetModuleHandle(NULL);
	printf("done.\n");

	// register window class
	printf("register window class...");
	WNDCLASS wndclass;
	wndclass.style			= 0x00000000;					// class share device context
	wndclass.lpfnWndProc	= WndProc;						// universal/unique processor
	wndclass.cbClsExtra		= 0;							// system default / no extra
	wndclass.cbWndExtra		= 0;							// system default / no extra
	wndclass.hInstance		= hinstance;					// handle of instance
	wndclass.hIcon			= LoadIcon(0, IDI_APPLICATION);	// default icon
	wndclass.hCursor		= LoadCursor(0, IDC_ARROW);		// default cursor
	wndclass.hbrBackground	= NULL;							// no background auto-paint
	wndclass.lpszMenuName	= NULL;							// no menu
	wndclass.lpszClassName	= "Default";					// name: for windows and dx use
	if(!RegisterClass(&wndclass))
	{
		return scope.Close(Boolean::New(false));
	}
	printf("done.\n");

	// create window
	printf("create window...");
	DWORD style = WS_CAPTION| WS_SYSMENU| WS_MINIMIZEBOX| WS_VISIBLE;
	RECT rc = {0, 0, SCREEN_WIDTH, SCREEN_HEIGHT};
	if(!AdjustWindowRect(&rc, style, FALSE))
	{
		return scope.Close(Boolean::New(false));
	}
	if(!(hwnd = CreateWindow(
		"Default",			// window class registered before
		title,				// caption
		style,				// minimizable, captionated, unsizable, visible
		100,				// x
		100,				// y
		rc.right - rc.left,	// width
		rc.bottom - rc.top,	// height
		NULL,				// no parent window
		NULL,				// no menu
		hinstance,			// this instance
		NULL				// no extra info
		)))
	{
		return scope.Close(Boolean::New(false));
	}
	printf("done.\n");

	return scope.Close(Boolean::New(true));
}

Handle<Value> Check(const Arguments& args)
{
	HandleScope scope;

	MSG msg = {};
	//check event
	if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
	{
		DispatchMessage(&msg);
		if(msg.message==WM_QUIT)
		{
			return scope.Close(Boolean::New(true));
		}
	}

	return scope.Close(Boolean::New(false));
}

Handle<Value> Alert(const Arguments& args)
{
	HandleScope scope;

	Local<String> msg = args[0]->ToString();
	wchar_t buf[256];
	msg->Write((uint16_t*)buf);
	MessageBoxW(GetActiveWindow(),buf,L"",MB_OK);
	
	return scope.Close(Null());
}

void init(Handle<Object> target)
{
	target->Set(String::NewSymbol("getTemp"),FunctionTemplate::New(GetTemp)->GetFunction());
	target->Set(String::NewSymbol("setTemp"),FunctionTemplate::New(SetTemp)->GetFunction());
	target->Set(String::NewSymbol("deleteTemp"),FunctionTemplate::New(DeleteTemp)->GetFunction());
	target->Set(String::NewSymbol("main"),FunctionTemplate::New(Main)->GetFunction());
	target->Set(String::NewSymbol("check"),FunctionTemplate::New(Check)->GetFunction());
	target->Set(String::NewSymbol("alert"),FunctionTemplate::New(Alert)->GetFunction());
}

NODE_MODULE(win32, init)